/**
 * @author phi
 */

(function(){ "use strict"; })();

(function(){
    /**
     * @namespace
     * @memberof    TM
     */
    TM.DOM = TM.DOM || {};
})();

/*
 * Event
 */
TM.loadScript("dom", "dom", function(){
    
    var Element = TM.DOM.Element;
    
    /**
     * イベントクラス.
     * @lends   TM.DOM.Event.prototype
     */
    var Event = TM.DOM.Event = TM.createClass({
        element     : null,
        funcList    : null,
        funcIndex   : 0,
        
        /**
         * @constructs
         * @see <a href="./../../test/dom/event-test.html">Test Program</a>.
         */
        init: function(element) {
            this.element = element;
            this.funcList = {};
        },
        
        /**
         * イベントを追加
         */
        add: function(type, fn, id) {
            var self = this;
            var elm  = TM.$DOMElement(this.element);
            
            var temp_fn = function(e) {
                // return fn.apply(self, arguments);
                var result = fn.apply(elm, arguments);
                
                if (result === false) {
                    // デフォルトイベントをキャンセル
                    e.preventDefault();
                    e.returnValue = false;  // IE
                    // イベント伝達をキャンセル
                    e.stopPropagation();
                }
                
                return result;
            }
            
            this._funcIndex = this._funcIndex || 0;
            id = id || this._funcIndex++;
            this.funcList[type] = this.funcList[type] || {};
            this.funcList[type][id] = temp_fn;
            fn._id = id;    // しれっと記録
            
            this.element.addEventListener(type, temp_fn, false);
            return this;
        },
        
        /**
         * イベントを解除
         */
        remove: function(type, fn_or_id) {
            var id = (typeof(fn_or_id) === "function") ? fn_or_id._id : fn_or_id;
            var fn = this.getFunc(type, id);
            
            this.element.removeEventListener(type, fn, false);
            delete this.funcList[type][id];
        },
        
        /**
         * クリックイベント
         */
        click: function(fn, id) {
            this.add("click", fn, id);
            return this;
        },
        
        /**
         * ホバーイベント
         */
        hover: function(fn, id) {
            this.add("mouseover", fn, id);
            return this;
        },
        
        /**
         * 一度だけ呼ばれるイベントを登録
         */
        one: function(type, fn, id) {
            var self = this;
            var elm  = TM.$DOMElement(this.element);
            
            var temp_fn = function() {
                var result = fn.apply(elm, arguments);
                self.remove(type, temp_fn);
                return result;
            };
            
            this.add(type, temp_fn, id);
            
            return this;
        },
        
        /**
         * トグルイベント登録
         */
        toggle: function(type, fn_list) {
            var self = this;
            var elm  = TM.$DOMElement(this.element);
            var temp_list = [];
            
            for (var i=0; i<fn_list.length; ++i) {
                var temp_fn = (function(i){
                    return function(){
                        var result = fn_list[i].apply(elm, arguments);
                        
                        if (result !== false) {
                            var index = (i+1)%fn_list.length;
                            self.one(type, temp_list[index]);
                        }
                    }
                })(i);
                temp_list.push(temp_fn);
            }
            
            this.one(type, temp_list[0]);
            
            return this;
        },
        
        /**
         * 指定したイベントタイプ & id の関数を取得
         */
        getFunc: function(type, id) {
            return this.funcList[type][id];
        }
    });
    
    /**
     * スタイルクラス
     * @name    event
     * @fieldof TM.DOM.Element.prototype
     * @type    TM.DOM.Event
     */
    Element.prototype.getter("event", function(){
        return this._event || ( this._event = Event(this.element) );
    });
    
    
    
    console.assert(!TM.$DOMEvent, "名前が競合しています!!", "$DOMEvent");
    /**
     * TM.DOM.Event の alias.
     * short hand としてお使いください.
     */
    TM.$DOMEvent = TM.DOM.Event;
    
});


